<!-- 树状选择器 -->
<template>
	<el-popover ref="popover" placement="bottom-start" trigger="click" @show="onShowPopover" @hide="onHidePopover">
		<el-tree ref="tree" class="select-tree" highlight-current :style="`min-width: ${treeWidth}`" :data="data"
			:props="props" :expand-on-click-node="false" :filter-node-method="filterNode" :default-expand-all="false"
			@node-click="onClickNode">
		</el-tree>
		<el-input slot="reference" ref="input" v-model="labelModel" clearable :style="`width: ${width}px`"
			:class="{ 'rotate': showStatus }" suffix-icon="el-icon-arrow-down" :placeholder="placeholder">
		</el-input>
	</el-popover>
</template>

<script>
	export default {
		name: 'SelectTree',
		props: {
			// 接收绑定参数
			value: String,
			// 输入框宽度
			width: String,
			// 选项数据
			options: {
				type: Array,
				required: true,
			},
			// 输入框占位符
			placeholder: {
				type: String,
				required: false,
				default: '请选择',
			},
			// 树节点配置选项
			props: {
				type: Object,
				required: false,
				default: () => ({
					parent: 'parentId',
					value: 'rowGuid',
					label: 'areaName',
					children: 'children',
				}),
			},
		},
		// 设置绑定参数
		model: {
			prop: 'value',
			event: 'selected',
		},
		computed: {
			// 是否为树状结构数据
			dataType() {
				const jsonStr = JSON.stringify(this.options);
				return jsonStr.indexOf(this.props.children) !== -1;
			},
			// 若非树状结构，则转化为树状结构数据
			data() {
				return this.dataType ? this.options : this.switchTree();
			},
		},
		watch: {
			labelModel(val) {
				if (!val) {
					this.valueModel = '';
				}
				this.$refs.tree.filter(val);
			},
			value(val) {
				this.labelModel = this.queryTree(this.data, val);
			},
		},
		data() {
			return {
				// 树状菜单显示状态
				showStatus: false,
				// 菜单宽度
				treeWidth: 'auto',
				// 输入框显示值
				labelModel: '',
				// 实际请求传值
				valueModel: '0',
			};
		},
		created() {
			// 检测输入框原有值并显示对应 label
			if (this.value) {
				this.labelModel = this.queryTree(this.data, this.value);
			}
			// 获取输入框宽度同步至树状菜单宽度
			this.$nextTick(() => {
				this.treeWidth = `${(this.width || this.$refs.input.$refs.input.clientWidth) - 24}px`;
			});
		},
		methods: {
			// 单击节点
			onClickNode(node) {
				this.labelModel = node[this.props.label];
				this.valueModel = node[this.props.value];
				this.onCloseTree();
			},
			// 偏平数组转化为树状层级结构
			switchTree() {
				return this.cleanChildren(this.buildTree(this.options, '0'));
			},
			// 隐藏树状菜单
			onCloseTree() {
				this.$refs.popover.showPopper = false;
			},
			// 显示时触发
			onShowPopover() {
				this.showStatus = true;
				this.$refs.tree.filter(false);
			},
			// 隐藏时触发
			onHidePopover() {
				this.showStatus = false;
				this.$emit('selected', this.valueModel);
			},
			// 树节点过滤方法
			filterNode(query, data) {
				if (!query) return true;
				return data[this.props.label].indexOf(query) !== -1;
			},
			// 搜索树状数据中的 ID
			queryTree(tree, id) {
				let stark = [];
				stark = stark.concat(tree);
				while (stark.length) {
					const temp = stark.shift();
					if (temp[this.props.children]) {
						stark = stark.concat(temp[this.props.children]);
					}
					if (temp[this.props.value] === id) {
						return temp[this.props.label];
					}
				}
				return '';
			},
			// 将一维的扁平数组转换为多层级对象
			buildTree(data, id = '0') {
				const fa = (parentId) => {
					const temp = [];
					for (let i = 0; i < data.length; i++) {
						const n = data[i];
						if (n[this.props.parent] === parentId) {
							n.children = fa(n.rowGuid);
							temp.push(n);
						}
					}
					return temp;
				};
				return fa(id);
			},
			// 清除空 children项
			cleanChildren(data) {
				const fa = (list) => {
					list.map((e) => {
						if (e.children.length) {
							fa(e.children);
						} else {
							delete e.children;
						}
						return e;
					});
					return list;
				};
				return fa(data);
			},
		},
	};
</script>

<style>
	.el-input.el-input--suffix {
		cursor: pointer;
		overflow: hidden;
	}

	.el-input.el-input--suffix.rotate .el-input__suffix {
		transform: rotate(180deg);
	}

	.select-tree {
		max-height: 350px;
		overflow-y: scroll;
	}

	/* 菜单滚动条 */
	.select-tree::-webkit-scrollbar {
		z-index: 11;
		width: 6px;
	}

	.select-tree::-webkit-scrollbar-track,
	.select-tree::-webkit-scrollbar-corner {
		background: #fff;
	}

	.select-tree::-webkit-scrollbar-thumb {
		border-radius: 5px;
		width: 6px;
		background: #b4bccc;
	}

	.select-tree::-webkit-scrollbar-track-piece {
		background: #fff;
		width: 6px;
	}
</style>
